package com.biz.primus.ms.homepage.service;


import com.biz.primus.base.enums.CommonStatus;
import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.common.utils.JsonUtils;
import com.biz.primus.homepage.enums.TimeRangePolicy;
import com.biz.primus.homepage.vo.CoverTemplateData;
import com.biz.primus.homepage.vo.ProgramDetailRespVo;
import com.biz.primus.homepage.vo.ProgramRoVo;
import com.biz.primus.homepage.vo.ProgramUpdateReqVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.homepage.dao.redis.CoverRedisDao;
import com.biz.primus.ms.homepage.dao.redis.ProgramRedisDao;
import com.biz.primus.ms.homepage.dao.ro.CoverRo;
import com.biz.primus.ms.homepage.dao.ro.ProgramRo;
import com.biz.primus.ms.homepage.trans.ProgramRo2ProgramRoVo;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;

import static java.util.stream.Collectors.toMap;

/**
 * Created by jiangnan on 2017/7/13.
 */
@Service
public class ProgramServerServiceImpl extends AbstractBaseService implements ProgramServerService {

    @Autowired
    private ProgramRedisDao programRedisDao;

    @Autowired
    private CoverRedisDao coverRedisDao;

    @Override
    public ProgramRoVo findOne(Long programId) {
        ProgramRo one = programRedisDao.findOne(programId);
        if (one == null) {
            return null;
        }
        return new ProgramRo2ProgramRoVo().apply(one);
    }

    @Override
    public ProgramRoVo save(ProgramUpdateReqVo reqVo) {
        ProgramRo ro;
        if (reqVo.getId() == null) {
            ro = new ProgramRo();
            ro.setId(idService.getNextId());
        } else {
            ro = programRedisDao.findOne(reqVo.getId());
        }
        ro.setCoverId(reqVo.getCoverId());
        ro.setParentId(reqVo.getParentId());
        ro.setName(reqVo.getName());
        ro.setDescription(reqVo.getDescription());
        ro.setSourceId(reqVo.getSourceId());
        ro.setDataJson(JsonUtils.obj2Json(reqVo.getCoverTemplateData()));
        ro.setStatus(reqVo.getStatus());
        ro.setTimeRangePolicy(reqVo.getTimeRangePolicy());
        ro.setStartTime(reqVo.getStartTime());
        ro.setEndTime(reqVo.getEndTime());
        ro.setUpdateTimestamp(DateUtil.now());
        programRedisDao.save(ro);
        return new ProgramRo2ProgramRoVo().apply(ro);
    }

    @Override
    public ProgramDetailRespVo getProgramDetail(Long programId) {
        ProgramRoVo programRo = findOne(programId);
        List<ProgramRoVo> programsOfCover = this.findByCoverId(programRo.getCoverId());
        Iterator<ProgramRoVo> iterator = programsOfCover.iterator();
        while (iterator.hasNext()) {
            ProgramRoVo tempProgram = iterator.next();
            if (tempProgram.getParentId() == null || !Objects.equals(tempProgram.getParentId(), programId)) {
                iterator.remove();
            }
        }
        return buildProgramDetailRespVo(programRo, programsOfCover);
    }

    List<ProgramRoVo> findByCoverId(String coverId) {
        List<ProgramRo> programsOfCover = programRedisDao.findByCoverId(coverId);
        return Lists.transform(programsOfCover, new ProgramRo2ProgramRoVo());
    }

    @Override
    public List<ProgramRoVo> getAllProgramsByCoverId(String coverId) {
        CoverRo coverRo = coverRedisDao.findOne(coverId);
        List<ProgramRo> programRos = programRedisDao.findByCoverId(coverId);
        Map<Long, ProgramRo> programRoMap = programRos.parallelStream().collect(toMap(ProgramRo::getId, Function.identity()));
        programRos.forEach((programRo) -> {
            if (programRo.getParentId() != null) {
                programRo.setParent(programRoMap.get(programRo.getParentId()));
            } else {
                if (programRo.getTimeRangePolicy() == TimeRangePolicy.INHERIT) {
                    programRo.setStartTime(coverRo.getStartTime());
                    programRo.setEndTime(coverRo.getEndTime());
                }
            }
        });
        return Lists.transform(programRos, new ProgramRo2ProgramRoVo());
    }

    @Override
    public void deleteProgramsByCoverId(String coverId) {
        programRedisDao.deleteByCoverId(coverId);
    }

    @Override
    public void delete(Long programId) {
        ProgramRo programRo = programRedisDao.findOne(programId);
        if (programRo != null) {
            programRedisDao.delete(programId);
            List<ProgramRo> otherProgramsOfThisCover = programRedisDao.findByCoverId(programRo.getCoverId());
            for (ProgramRo ro : otherProgramsOfThisCover) {
                if (Objects.equals(ro.getParentId(), programId)) {
                    delete(ro.getId());
                }
            }
            ;
        }

    }


    /**
     * 根据coverId取出对应的所有program
     * 然后构造CoverTemplateData
     *
     * @param coverId
     * @param enableAllProgram
     * @return
     */
    @Override
    public CoverTemplateData getCoverTemplateDataByCoverId(String coverId, Boolean enableAllProgram) {
        List<ProgramRoVo> programs = getAllProgramsByCoverId(coverId);
        CoverTemplateData coverTemplateData = new CoverTemplateData();
        Map<Long, ProgramDetailRespVo> programIdToCoverTemplateData =
                programs.stream().filter((program) -> !(enableAllProgram || Objects.equals(program.getStatus(), CommonStatus.ENABLE)
                        && program.atTheRightTime())).collect(toMap(ProgramRoVo::getId, (p) -> buildProgramDetailRespVo(p, null)));
        for (Map.Entry<Long, ProgramDetailRespVo> idProgramDetailRespVoMapping : programIdToCoverTemplateData.entrySet()) {
            ProgramDetailRespVo programDetailRespVo = idProgramDetailRespVoMapping.getValue();
            ProgramRoVo program = programDetailRespVo.getProgram();
            if (program.getParentId() == null) {
                coverTemplateData.add(program.getSourceId(), programDetailRespVo.getCoverTemplateData());
            } else if (programIdToCoverTemplateData.containsKey(program.getParentId())) {
                programIdToCoverTemplateData.get(program.getParentId()).getCoverTemplateData().add(program.getSourceId(),
                        programDetailRespVo.getCoverTemplateData());
            }
        }
        return coverTemplateData;
    }

    ProgramDetailRespVo buildProgramDetailRespVo(ProgramRoVo programRo, List<ProgramRoVo> subPrograms) {
        ProgramDetailRespVo respVo = new ProgramDetailRespVo();
        respVo.setProgram(programRo);
        if (programRo != null) {
            CoverTemplateData coverTemplateData = JsonUtils.json2Obj(programRo.getDataJson(), CoverTemplateData.class);
            respVo.setCoverTemplateData(coverTemplateData);
            if (CollectionUtils.isNotEmpty(subPrograms)) {
                respVo.setSubPrograms(subPrograms);
                for (ProgramRoVo ro : subPrograms) {
                    respVo.getCoverTemplateData().add(ro.getSourceId(), coverTemplateData);
                }
            }
        }
        return respVo;
    }


}
